/*"validate","initValidator",*/
/* 验证辅助方法 */
var _formatMsg = function(src, args){
    if(args.constructor != Array){
        args = [args];
    }
    $.each(args, function(i, n){
        src = src.replace(new RegExp('\\{' + i + '\\}', 'g'), n);
    });
    return src;
};
/**
 * @widoc $.fn.validate
 * @namespace aux
 * @des 验证当前元素
 * @type function
 * @param {object} rules 要验证的表单元素的验证规则，键值对
 *     rules.key: 验证规则名称
 *     rules.value: 验证规则对应的参数
 * @param {object=} messages 自定义提示
 *     messages.key: 验证规则名称
 *     messages.value: 对应规则验证不通过时显示的自定义提示，若为 false，则不会提示验证信息
 * @param {function=} cb 验证不通过时再次点击元素时的回调函数
 * @param {boolean=} bindBlur 是否绑定失焦验证的事件，默认为 true，非特殊情况不需定义此属性
 * @return {boolean} 是否通过验证
 */
$.fn.validate = function(rules, messages, cb, bindBlur){// el 要添加danger样式的元素
    var el = $(this);
    var _errCls = 'dangerI'
        , _blurValEv = 'blur._validate'
        , _clickValEv = 'tap._valiTip';
    var tagEl = el.parent('.wi-date,.wi-dp,.wi-combo').length
        ? el.parent()// 日期、下拉框组件样式需加在父元素
        : el;
    el.off(_blurValEv);
    tagEl.off(_clickValEv);
    if(bindBlur != false){
        el.on(_blurValEv, function(){// 失焦时根据规则校验-暂只考虑文本框
            el.validate(rules, messages, cb);
        });
    }
    var errorRule = '';
    for(var rule in rules){// 逐个验证 rules
        if(rules.hasOwnProperty(rule)){
            var method = $.validator.methods[rule];
            if(method && !method(rules[rule], el)){// 定义了该验证方法且验证结果为 false
                errorRule || (errorRule = rule);
                break;
            }
        }
    }
    if(errorRule == ''){
        tagEl.removeClass(_errCls);
        // 自定义验证规则时，可能会重新加上这些事件，慎重考虑是否可以删除
        el.off(_blurValEv);
        tagEl.off(_clickValEv);
        return true;
    }
    else{
        tagEl.addClass(_errCls);
        // 2017.10.18 支持 message 设为 false，此时点击不显示提示信息
        //var msg = (messages && messages[errorRule]) ?
        //    messages[errorRule] :
        //$.validator.messages[errorRule] || '校验未通过';
        var msg;
        if(messages){// 先从用户自定义属性中获取配置
            msg = messages[errorRule];
        }
        if(!msg && msg !== false){// 若为 false 不需修改
            msg = $.validator.messages[errorRule];
        }
        if(!msg && msg !== false){// 若为 false 不需修改
            msg = '校验未通过';
        }
        msg = _formatMsg(msg, rules[errorRule]);
        if(msg !== false){// 需要显示验证提示
            tagEl.on(_clickValEv, (function(msg){
                return function(){
                    if(cb){
                        cb(tagEl, msg);
                    }
                    else{
                        //$.showValiTip(tagEl,msg);// showValiTip 会因小键盘弹出错位
                        appcan.window.openToast(msg, '2000');// TODO 显示验证信息
                    }
                };
            })(msg));
        }
        return false;
    }
};
/**
 * @widoc $.fn.initValidator
 * @namespace aux
 * @des 对元素子孙元素中的表单元素初始化验证条件。验证触发后，验证不通过时将对该表单元素的 class 添加 "dangerI"
 * @type function
 * @param options
 * @param {object} options.rules 验证规则，键值对
 *      key: 要验证的表单元素的 name 属性的值
 *      value {object}: 要验证的表单元素的验证规则，键值对
 *          key: 验证规则名称
 *          value: 验证规则对应的参数
 * @param {object=} options.messages 自定义验证信息，键值对
 *      key: 要验证的表单元素的 name 属性的值
 *      value {object}: 验证不通过时显示的自定义提示
 * @param {function} options.callback(el,msg) 自定义提示方法
 *      el {string} 验证失败的元素
 *      msg {string} 该元素上的提示信息
 * @param {boolean} options.autoScroll 验证失败时，是否自动滚动到第一个验证失败的元素，默认为 true
 * @return {object|undefined} returnObj 接口对象
 * @rtn {function} returnObj.validateAll() 手动触发当前元素内表单验证的方法
 * @rtn {function} returnObj.resetAllRules() 恢复所有元素的验证规则
 * @rtn {function} returnObj.removeAllRules(validate) 移除所有元素的验证规则
 *      validate {boolean=} 移除部分规则后，是否立即重新验证该元素，默认为 true
 * @rtn {function} returnObj.removeRules(name,rules,validate) 移除指定name的元素的验证规则
 *      name {string} 要移除验证规则的元素的 name，也对应初始化时 opts.rules 及 opts.messages 中的key
 *      rules {Array=} 要移除的规则名数组，若未定义则移除全部规则
 *      validate {boolean=} 移除部分规则后，是否立即重新验证该元素，默认为 true
 * @rtn {function} returnObj.addRules(addopts,validate) 添加指定name的元素的验证规则
 *      addopts {object} 同初始化时的 options（但不含 callback）
 *      validate {boolean=} 添加部分规则后，是否立即重新验证全部元素，默认为 true
 * @rtn {function} returnObj.resetValStat() 恢复所有验证状态
 */
$.fn.initValidator = function(options){
    if(!options || !options.rules) return;
    options = $.extend({
        autoScroll: true// valiadateAll() 验证失败时，是否自动滚动到第一个验证失败的元素
    }, options);
    var rules, messages,
        form = $(this);
    var _errCls = 'dangerI',
        _blurValEv = 'blur._validate',
        _clickValEv = 'click._valiTip';// 与 $.fn.validate 一致
    var _validate = function(name){
        var rulesOnEl = rules[name];
        if(!rulesOnEl) return true;// 此元素上未定义规则，验证通过
        var messagesOnEl = messages ? messages[name] : undefined;
        var curEl = form.find('[name="' + name + '"]');
        return !curEl.length || curEl.validate(rulesOnEl, messagesOnEl, options.callback, false);
    };
    var _validateAll = function(){
        var status = true;
        for(var name in rules){
            if(rules.hasOwnProperty(name)){
                if(_validate(name) == false){// 对此元素定义了规则且验证未通过
                    status = false;
                }
            }
        }
        if(!status && options.autoScroll){
            form.find('.dangerI')[0].scrollIntoView();// 将第一个验证失败的元素滚动到视图内
        }
        return status;
    };
    var _init = function(){
        form
            .off(_blurValEv)
            .on(_blurValEv, '[data-validate="true"]', function(){// 失焦时根据规则校验-暂只考虑文本框
                _validate($(this).attr('name'));
            })
            .off('submit.vali')
            .on('submit.vali', _validateAll);
        _resetAllRules(options.rules, options.messages);
    };
    var _removeAllRules = function(){
        for(var name in rules){
            if(rules.hasOwnProperty(name)){
                _removeRules(name);
            }
        }
    };
    var _resetAllRules = function(_rules, _msgs){
        _removeAllRules();
        if(!_rules) return;
        rules = _rules;
        messages = _msgs;
        for(var name in rules){
            if(rules.hasOwnProperty(name)){// 设置需要验证的表单元素的属性
                form.find('[name="' + name + '"]').attr('data-validate', 'true');
            }
        }
    };
    /**
     * 移除指定name的元素的验证规则
     * @param name {string} 要移除验证规则的元素的 name，也对应初始化时 options.rules 及 options.messages 中的key
     * @param removeRules {Array=} 要移除的规则名数组，若未定义则移除全部规则
     * @param validate {boolean=} 移除部分规则后，是否立即重新验证该元素，默认为 true
     * @private
     */
    var _removeRules = function(name, removeRules, validate){
        var el = form.find('[name="' + name + '"]');
        var rulesOnEl = rules[name];
        var hasProp = false;// 标记移除部分规则后是否还存在验证规则
        if(rulesOnEl && removeRules && removeRules.length){// 解绑指定规则
            for(var i = 0, len = removeRules.length; i < len; i++){
                delete rulesOnEl[removeRules[i]];
            }
            for(var rName in rulesOnEl){
                hasProp = true;// 存在验证规则
                break;
            }
        }
        else{// 解绑全部规则
            rulesOnEl = undefined;
        }
        var tagEl = el.parent('.wi-date,.wi-dp,.wi-combo').length
            ? el.parent()// 日期、下拉框组件样式需加在父元素
            : el;
        tagEl.removeClass(_errCls);// 删除原验证状态
        tagEl.off(_clickValEv);
        if(!hasProp){
            el.removeAttr('data-validate');
            delete rules[name];
        }
        else if(validate != false){// 有规则，并定义了立即重新验证
            _validate(name);
        }
    };
    /**
     * 移除指定name的元素的验证规则
     * @param addOpts {object} 同初始化时的 options（但不含 callback）
     * @param validate {boolean=} 移除部分规则后，是否立即重新验证全部元素，默认为 true
     * @private
     */
    var _addRules = function(addOpts, validate){
        var _rules = addOpts.rules
            , _messages = addOpts.messages;
        for(var name in _rules){
            if(_rules.hasOwnProperty(name)){// 设置需要验证的表单元素的属性
                var el = form.find('[name="' + name + '"]');
                var tagEl = el.parent('.wi-date,.wi-dp,.wi-combo').length
                    ? el.parent()// 日期、下拉框组件样式需加在父元素
                    : el;
                el.attr('data-validate', 'true');
                rules[name] = rules[name] ?
                    $.extend(rules[name], _rules[name]) : _rules[name];
                if(validate == false){// 不立即验证，取消之前的验证结果
                    tagEl.removeClass(_errCls);// 删除原验证状态，与 $.fn.validate 中一致
                    tagEl.off(_clickValEv);// 与 $.fn.validate 中一致
                }
            }
        }
        if(_messages){
            if(_messages.hasOwnProperty(name)){
                messages[name] = messages[name] ?
                    $.extend(messages[name], _messages[name]) : _messages[name];
            }
        }
        if(validate != false){// 立即验证全部
            _validateAll();
        }
    };
    /**
     * 恢复所有验证状态
     * @private
     */
    var _resetValStat = function(){
        form.find('[data-validate="true"]')
            .off(_clickValEv);
        form.find('.' + _errCls).removeClass(_errCls);// _errCls 可能加在 [data-validate] 元素的父元素：.wi-date,.wi-dp,.wi-combo
    };
    var _returnObj = {
        el: form,
        validateAll: _validateAll,
        resetAllRules: _resetAllRules,
        removeAllRules: _removeAllRules,
        removeRules: _removeRules,
        addRules: _addRules,
        resetValStat: _resetValStat
    };
    _init();
    return _returnObj;
};